# -*- coding: utf-8 -*-

from hlm.node import *

from ip.fabrics import ChannelTranOpFabric, ChannelLoadReqFabric


class NodeTRunner(Node):
    def initialize(self, params: ObjectDict) -> None:
        params.num_of_main_memory: int
        params.multiplexer: int
        # Save the multiplexer.
        self.const.multiplexer = params.multiplexer
        self.const.num_of_main_memory = params.num_of_main_memory
        # Save the settings.
        self.reg.is_running = False
        # Prepare the port for nano-op receiver.
        self.port.nano_op_receiver = self.port_channel_receiver(ChannelTranOpFabric)
        # Prepare the port to main memory.
        self.port.memory_ports = [self.port_channel_sender(ChannelLoadReqFabric)
                                  for _ in range(params.num_of_main_memory)]

    tasks = ['task_fetch_op', 'task_dispatch_execution']

    def task_fetch_op(self):
        # Check running state.
        if self.reg.is_running or self.port.nano_op_receiver.Bus.is_any_empty():
            return
        # Fetch the nano op.
        self.reg.nano_op = self.port.nano_op_receiver.Bus.get()
        # Clear the registers.
        self.reg.len = 0
        self.reg.src_addr = self.reg.nano_op.src_addr
        self.reg.dst_addr = self.reg.nano_op.dst_addr
        self.reg.is_running = True

    def task_dispatch_execution(self):
        for _ in range(self.const.multiplexer):
            # Check running state.
            if not self.reg.is_running:
                return
            # Check whether the is a memory controller is valid.
            for ii in range(self.const.num_of_main_memory):
                # Check whether the Bus is full.
                if self.port.memory_ports[ii].Bus.is_any_full():
                    continue
                # Okay, one valid port is found.
                if self.reg.len >= self.reg.nano_op.len_limit:
                    # Clear the working state.
                    self.reg.is_running = False
                    return
                # Deploy the request.
                self.port.memory_ports[ii].Bus.put(
                    mem_addr=self.reg.src_addr,
                    pid=self.reg.nano_op.dst_peer_id,
                    sm_addr=self.reg.dst_addr,
                    sb_addr=self.reg.nano_op.dst_sb_addr,
                    ain_addr=self.reg.nano_op.dst_ain_addr,
                    clr=self.reg.nano_op.dst_clear)
                # Move to next position.
                self.reg.src_addr += self.reg.nano_op.src_stride
                self.reg.dst_addr += self.reg.nano_op.dst_stride
                # Increase the length.
                self.reg.len += 1